﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
using Xms.Abp.Data.Message;

namespace Xms.Abp.Smsing
{
    public class TemplateSmsSender: SmsSenderBase, ITransientDependency
    {
        protected IEnumerable<ITemplateSmsSenderProvider> Providers { get; }
        protected SmsSettings SmsSettings { get; }
        protected IServiceProvider Services { get; }
        protected ILogger<TemplateSmsSender> Logger { get; }
        protected IJsonSerializer JsonSerializer { get; }
        public TemplateSmsSender(
            IBackgroundJobManager backgroundJobManager,
            IEnumerable<ITemplateSmsSenderProvider> providers,
            SmsSettings smsSettings,
            IServiceProvider services,
            ILogger<TemplateSmsSender> logger,
            IJsonSerializer jsonSerializer
            )
            : base(backgroundJobManager)
        {
            Providers = providers;
            SmsSettings = smsSettings;
            Services = services;
            Logger = logger;
            JsonSerializer = jsonSerializer;
        }
        public override async Task QueueAsync(SmsMessage smsMessage)
        {
            ReplacePlaceHoldersAndFormatParameters(smsMessage);
            await base.QueueAsync(smsMessage);
        }

        protected override async Task SendSmsAsync(SmsMessage smsMessage)
        {
            var result = await DoSendSmsAsync(smsMessage);
            var store = Services.GetService<ISmsMessageStore>();
            if (store == null)
            {
                Logger.LogWarning("[{SpecialCode}]短信未持久化保存，内容：", "SendSms", JsonSerializer.Serialize(new
                {
                    SmsMessage = smsMessage,
                    SendResult = result
                }));
            }
            else
            {
                try
                {
                    await store.SaveMessageAsync(smsMessage, result);
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, "[{SpecialCode}]短信持久化失败：", "SendSms", JsonSerializer.Serialize(new
                    {
                        SmsMessage = smsMessage,
                        SendResult = result
                    }));
                }
            }
        }

        public virtual void ReplacePlaceHoldersAndFormatParameters(SmsMessage smsMessage)
        {
            var text = smsMessage.Template;
            IDictionary<string, string> parameters = smsMessage.TemplateParameters;
            foreach (var key in parameters.Keys.ToArray())
            {
                text = text.Replace($"{{{{{key}}}}}", parameters[key]);
            }
            if (text.Contains("{{") && text.Contains("}}"))
            {
                throw new ArgumentException("未知参数：" + text.Split(new string[] { "{{", "}}" }, StringSplitOptions.None)[1]);
            }
            var dict = parameters.ToDictionary(r => r.Key, r => r.Value);
            var keys = smsMessage.ParameterNames;
            parameters.Clear();
            foreach (var key in keys)
            {
                if (!dict.ContainsKey(key))
                {
                    throw new ArgumentNullException(key);
                }
                parameters[key] = dict[key];
            }
            smsMessage.Template = text;
        }

        public override void ValidateTemplateParameters(IDictionary<string, string> templateParameters, string[] parameterNames)
        {
            var parameters = new Dictionary<string, string>();
            foreach (var name in parameterNames)
            {
                if (!templateParameters.ContainsKey(name))
                {
                    throw new ArgumentNullException(name);
                }
                parameters[name] = templateParameters[name];
            }
            templateParameters.Clear();
            foreach (var kv in parameters)
            {
                templateParameters.Add(kv);
            }
        }

        private async Task<SentResult<SmsSentResultItem>> DoSendSmsAsync(SmsMessage smsMessage)
        {
            var providers = Providers.Where(r => r.IsEnabled);
            if (!providers.Any())
            {
                return new SentResult<SmsSentResultItem>
                {
                    Items = smsMessage.PhoneNumbers.Select(r => new SmsSentResultItem { PhoneNumber = r, SentStatus = SentStatus.Faild, ErrorCode = "NotFoundProvider", Message = "短信发送未设置可用的发送提供器" })
                };
            }
            var provider = providers.FirstOrDefault(r => r.ProviderName == SmsSettings.DefaultProvider);
            if (provider == null)
            {
                Logger.LogWarning("[{SpecialCode}]短信发送未设置默认发送提供器，或默认发送提供器未启用！", "SendSms");
                provider = providers.FirstOrDefault();
            }
            var sms = smsMessage;
            if (SmsSettings?.IsForwordEnabled ?? false)
            {
                var dict = SmsSettings.Forwords;
                if (dict.Count > 0)
                {
                    var phones = sms.PhoneNumbers;
                    var newPhones = phones.Select(r=> SmsSettings.Forwords[r]);
                    if (newPhones.Any(r => !phones.Contains(r)))
                    {
                        sms = new SmsMessage
                        {
                            ClientId = smsMessage.ClientId,
                            ParameterNames = smsMessage.ParameterNames,
                            PhoneNumbers = newPhones.ToArray(),
                            Priority = smsMessage.Priority,
                            Template = smsMessage.Template,
                            TemplateCode = smsMessage.TemplateCode,
                            TemplateParameters = smsMessage.TemplateParameters,
                            TenantId = smsMessage.TenantId,
                        };
                    }
                }
            }
            if (!SmsSettings.IsErrorAutoSwitchProvider)
            {
                return await provider.SendSmsAsync(sms);
            }
            return await DoSendSmsAndTraySwitchAsync(sms, provider, providers.Where(r => r != provider));
        }

        private async Task<SentResult<SmsSentResultItem>> DoSendSmsAndTraySwitchAsync(SmsMessage smsMessage, ITemplateSmsSenderProvider provider, IEnumerable<ITemplateSmsSenderProvider> providers)
        {
            try
            {
                return await provider.SendSmsAsync(smsMessage);
            }
            catch (Exception ex)
            {
                //发送失败切换运营商
                if (providers.Any())
                {
                    var oldName = provider.ProviderName;
                    provider = providers.First();
                    Logger.LogWarning(ex, $"[{{SpecialCode}}]使用短信发送提供器{oldName}发送短信时报错，正在切换使用提供器{provider.ProviderName}！", "SendSms");
                    return await DoSendSmsAndTraySwitchAsync(smsMessage, provider, providers.Where(r => r != provider));
                }
                else
                {
                    throw;
                }
            }
        }
    }
}
